﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Permissions;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Web.Hosting;
using Sp.WebHost.NetFramework;

namespace Sp.WebHost
{
     [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
    public class WebServer : MarshalByRefObject, IDisposable
    {
         public int Port { get;private set; }
         public string PhysicalPath { get; private set; }
         public bool RequireAuthentication { get; private set; }
         public bool DisableDirectoryListing { get; private set; }

         private readonly ServerSocket _serverSocket = new ServerSocket(100, 1024);
         private Host _host = null;
         private readonly object _syncRoot = new object();
         private const string VirtualPath = "/";
         private readonly ApplicationManager _appManager;
         /// <summary>
         /// 构造跨平台Web服务器
         /// </summary>
         /// <param name="port">端口</param>
         /// <param name="physicalPath">网站应用路径</param>
         /// <param name="requireAuthentication">是否需要认证</param>
         /// <param name="disableDirectoryListing">是否显示网站文件列表</param>
         /// <param name="startNow">立即启动</param>
         public WebServer(int port, string physicalPath, bool requireAuthentication,
             bool disableDirectoryListing, bool startNow)
         {
             Port = port;
             PhysicalPath = Path.GetFullPath(string.IsNullOrWhiteSpace(physicalPath) ? "." : physicalPath).TrimEnd(Path.DirectorySeparatorChar)+ Path.DirectorySeparatorChar;
             RequireAuthentication = requireAuthentication;
             DisableDirectoryListing = disableDirectoryListing;
             _appManager = ApplicationManager.GetApplicationManager();
             _serverSocket.OnClientRead += _serverSocket_OnClientRead;
             _serverSocket.Init();
             if (startNow)
             {
                 _serverSocket.Start(port);

             }
         }

         private void _serverSocket_OnClientRead(object sender, AsyncUserToken e)
         {
             var conn = new Connection(_serverSocket, e);
             var lst = new byte[e.BytesReceived];
             Array.Copy(e.ReceiveBuffer, e.Offset, lst, 0, e.BytesReceived);
             var vts = Encoding.UTF8.GetString(lst);
             e.DataBuffer.AddRange(lst);
             if (e.Socket.Available <= 0) //
             {
                 if (!conn.ProduceIfError())
                 {
                     try
                     {
                         var host = GetHost();
                         host.ProcessRequest(conn);
                     }
                     catch (Exception ex)
                     {

                         string exception = string.Format(Constants.UnhandledException, e.GetType().ToString());
                         conn.WriteEntireResponseFromString(500, "Content-type:text/html;charset=utf-8\r\n",
                             Messages.FormatExceptionMessageBody(exception, ex.Message, ex.StackTrace), true);

                     }
                 }
             }

         }

         public void Start()
         {
             _serverSocket.Start(Port);
         }

         private Host GetHost()
         {
            
             var host = _host;

             if (host == null)
             {
                 lock (this._syncRoot)
                 {
                     host = _host;

                     if (host == null)
                     {
                         string text = (VirtualPath + PhysicalPath).ToLowerInvariant();
                         string appId = text.GetHashCode().ToString("x", CultureInfo.InvariantCulture);

                         var appDomain = _appManager.GetRunningApplications();
                         _host = (Host)_appManager.CreateObject(appId, typeof(Host), VirtualPath, PhysicalPath, false);
                         _host.Configure(this, this.Port, VirtualPath, this.PhysicalPath, RequireAuthentication, DisableDirectoryListing);

                         host = _host;
                     }
                 }
             }

             return host;
         }
         internal void HostStopped()
         {
             _host = null;
         }

         internal IntPtr GetProcessToken()
         {
             return IntPtr.Zero;
         }

         internal string GetProcessUser()
         {
             return WindowsIdentity.GetCurrent().Name;
         }


         [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
         public override object InitializeLifetimeService()
         {
             return null;
         }

         public void Dispose()
        {
            throw new NotImplementedException();
        }
    }
}
